package com.zxy.supplier_system.server.repository

import com.zxy.supplier_system.server.controller.ProcurementSupplierPaymentRecordController
import com.zxy.supplier_system.server.entity.ProcurementPaymentRecord
import com.zxy.supplier_system.server.entity.ProcurementSupplier
import com.zxy.supplier_system.server.entity.SystemService
import com.zxy.supplier_system.server.utils.SpecificationUtils
import com.zxy.supplier_system.server.utils.joinOnce
import jakarta.persistence.EntityManager
import jakarta.persistence.PersistenceContext
import org.springframework.data.jpa.domain.Specification
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaSpecificationExecutor
import java.math.BigDecimal
import java.time.OffsetDateTime

interface ProcurementPaymentRecordRepository : JpaRepository<ProcurementPaymentRecord, Int>,
    JpaSpecificationExecutor<ProcurementPaymentRecord>, CustomProcurementPaymentRecordRepository {

    fun deleteProcurementPaymentRecordByIdAndSupplier_SystemService(id: Int, systemService: SystemService)

    companion object {

        fun supplierIdEqual(supplierId: Int?): Specification<ProcurementPaymentRecord> {
            return if (supplierId == null)
                SpecificationUtils.empty<ProcurementPaymentRecord>()
            else
                Specification { root, query, criteriaBuilder ->
                    criteriaBuilder.equal(
                        root.joinOnce<ProcurementPaymentRecord, ProcurementSupplier>("supplier").get<Int>("id"),
                        supplierId
                    )
                }
        }

        fun paidDateTimeBefore(dateTime: OffsetDateTime?): Specification<ProcurementPaymentRecord> {
            if (dateTime == null) return SpecificationUtils.empty()
            return Specification { root, query, c ->
                c.lessThanOrEqualTo(root.get<OffsetDateTime>("paidDateTime"), dateTime)
            }
        }

        fun systemServiceEqual(systemService: SystemService): Specification<ProcurementPaymentRecord> {
            return SystemServiceRepository.Specifications.systemServiceEquals({ root ->
                root.joinOnce<ProcurementPaymentRecord, ProcurementSupplier>(
                    "supplier"
                )
            }, systemService)
        }
    }

}

interface CustomProcurementPaymentRecordRepository {
    fun sumTotalPaidMoney(
        supplierId: Int,
        request: ProcurementSupplierPaymentRecordController.QueryProcurementPaymentRecordRequest,
        systemService: SystemService
    ): BigDecimal
}

class CustomProcurementPaymentRecordRepositoryImpl : CustomProcurementPaymentRecordRepository {
    @PersistenceContext
    private lateinit var entityManager: EntityManager

    override fun sumTotalPaidMoney(
        supplierId: Int,
        request: ProcurementSupplierPaymentRecordController.QueryProcurementPaymentRecordRequest,
        systemService: SystemService
    ): BigDecimal {
        val criteriaBuilder = entityManager.criteriaBuilder
        val query = criteriaBuilder.createQuery()
        val root = query.from(ProcurementPaymentRecord::class.java)
        query.select(criteriaBuilder.sum<BigDecimal>(root.get<BigDecimal>("money")))



        query.where(
            Specification.allOf(
                ProcurementPaymentRecordRepository.systemServiceEqual(systemService),
                ProcurementPaymentRecordRepository.supplierIdEqual(supplierId),
                ProcurementPaymentRecordRepository.paidDateTimeBefore(request.endPaidDateTime)
            ).toPredicate(root, query, criteriaBuilder)
        )

        return (entityManager.createQuery(query).singleResult as BigDecimal?) ?: BigDecimal.ZERO
    }
}